package Tests;

import static org.junit.Assert.assertTrue;

import java.util.Random;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import Model.Player;
import Model.RandomEvent;

/**
 * @author Philip Pecher
 */

public class RandomEventTest {
	private Player[] players;
	private RandomEvent re;
	private Random r;
	private final static double SIGMASQUARED = .27 * (1 - .27);
	private final static double TOLERANCE = 2;
	private final static double ITERATIONS = 10000;

	/**
	 * Sets up needed objects
	 */
	@Before
	public void initTestElements() {
		re = new RandomEvent();
		r = new Random();
		players = new Player[4];
		Player p1 = new Player();
		Player p2 = new Player();
		Player p3 = new Player();
		Player p4 = new Player();
		players[0] = p1;
		players[1] = p2;
		players[2] = p3;
		players[3] = p4;
	}

	/**
	 * Check if all players roughly get the expected amount of events if they have random scores assigned to them.
	 */
	@Test
	public void randomizeScoresAndTestProportion() {
		int winCount = 0;
		for (int i = 0; i < ITERATIONS; i++) {
			setRandomScores();
			winCount += (re.eventOccurs(players[r.nextInt(players.length)],
					players)) ? 1 : 0;
		}
		assertTrue((double) winCount / ITERATIONS > .27 - TOLERANCE * SIGMASQUARED
				|| (double) winCount / ITERATIONS < .27 + TOLERANCE * SIGMASQUARED);
	}

	/**
	 * Check that the lowest scored player does not have an event triggered.
	 */
	@Test
	public void setLowestScoreAndTestNoEvents() {
		int winCount = 0;
		for (int i = 0; i < ITERATIONS; i++) {
			setLowestPlayerScore(0);
			winCount += (re.eventOccurs(players[0], players)) ? 1 : 0;
		}
		assertTrue(winCount == 0);
	}
	/**
	 * Free up objects that were used.
	 */
	@After
	public void cleanUp() {
		players = null;
		re = null;
		r = null;
	}
	/**
	 * Assign random scores to players between 0 and 999
	 */
	public void setRandomScores() {
		for (int i = 0; i < 4; i++)
			players[i].setScore(r.nextInt(1000));
	}
	/**
	 * Assign the given player's (0-based) score to 0 and everyone else's higher.
	 * @param: The player whose score score should be set to 0 (0-based indexing)
	 */
	public void setLowestPlayerScore(int playerIndex) {
		setRandomScores();
		players[playerIndex].setScore(0);
	}
}